local modname = "herta"
local playerinfo = {
    prefabname = "herta",
    ezsetup = {
        ignorecurse = false, --免疫猴子诅咒
    },
    common_postinit = function(inst)

    end,
    master_postinit = function(inst)

    end,
    prefabinfo = {
        startinv   = { -- ['goldnugget'] = {
            -- 	num = 4, -- 数量
            -- 	moditem = false, -- 是否为mod物品
            -- 	-- img = {atlas = 'images/inventoryimages/goldnugget.xml', image = 'goldnugget.tex'},
            -- },
        },
        maxhealth  = 200,
        maxsanity  = 200,
        maxhunger  = 200,
        soundsname = 'wendy',
    },
    avatar_info = {
        ['chs'] = {
            titles = "大黑塔",
            names = "大黑塔",
            descriptions = "*天才俱乐部#83\n*智识的令使",
            quotes = "\'人美衣美心更美的黑塔女士\'",
            survivability = "轻松",
            -- 描述
            myname = '我叫啥', -- 角色名
            others_desc_me = '你叫我啥', -- 其他人描述我
            me_desc_another_me = '%s,你是世界上的另一个我嘛?', -- 自己描述自己
        },
        ['en'] = {
            titles = "Herta",
            names = "herta",
            descriptions = "*Light Yume\n*Raindrop",
            quotes = "\'Light Yume Raindrop\'",
            survivability = "Strong",
            -- desc
            myname = 'My name is',                          -- avatar name
            others_desc_me = 'You are a good character',    -- other people describe me
            me_desc_another_me = '%s, are you another me?', -- describe another me
        },
    },
    skins = {
        default = {
            name = '大黑塔', -- 皮肤的名称
            des = '*天才俱乐部#83\n*智识的令使', -- 皮肤界面的描述
            quotes = '\'人美衣美心更美的黑塔女士\'', -- 选人界面的描述
            rarity = '典藏', -- 珍惜度 官方不存在的珍惜度则直接覆盖字符串
            rarityorder = 2, -- 珍惜度的排序 用于按优先级排序 基本没啥用
            raritycorlor = { 189 / 255, 73 / 255, 73 / 255, 1 }, -- {R,G,B,A}
        },
        extraskin = {},
    },
    --一些额外的皮肤资源
    extraplayerassets = {},
}
local language = GetModConfigData('lang_' .. modname) or "chs"
local MOD_util = {}
do
    --这个直接复制到对应的位置执行就行
    --执行时机是加载模组的时候
    local registerlist = {}
    local oldLoadPrefabFile = GLOBAL.LoadPrefabFile
    function GLOBAL.LoadPrefabFile(filename, async_batch_validation, search_asset_first_path, ...)
        if registerlist[filename] then
            assert(not async_batch_validation or not search_asset_first_path,
                "search_asset_first_path and async_batch_validation cannot both be defined")
            local fn = registerlist[filename]
            assert(fn, "Could not load file ")
            assert(type(fn) == "function", "Prefab file doesn't return a callable chunk: " .. filename)
            setfenv(fn, GLOBAL)
            local ret = { fn() }
            if ret then
                for i, val in ipairs(ret) do
                    if type(val) == "table" and val.is_a and val:is_a(GLOBAL.Prefab) then
                        val.search_asset_first_path = search_asset_first_path
                        if async_batch_validation then
                            RegisterPrefabsImpl(val, function(prefab, asset)
                                TheSim:AddBatchVerifyFileExists(asset.file)
                            end)
                        else
                            RegisterSinglePrefab(val)
                        end
                        GLOBAL.PREFABDEFINITIONS[val.name] = val
                    end
                end
            end

            return ret
        end
        return oldLoadPrefabFile(filename, async_batch_validation, search_asset_first_path, ...)
    end

    function MOD_util:RegisterModPrefab(prefab_path, prefabfn)
        registerlist["prefabs/" .. prefab_path] = prefabfn
        table.insert(PrefabFiles, prefab_path)
    end
end
do
    -------------------------------------------------------------------------
    --------------------- 感谢风铃大佬的奉献！！！---------------------------
    -------------------------------------------------------------------------
    local CreatePrefabSkin -- 重新定义一下自己的 试图绕过Modded API的截取 在文件结尾有重新定义
    local recipe_help = true
    local thank_help = true
    -- 人物皮肤API
    local characterskins = {}
    --[[格式 skinname = {
        打*的为必填项 反之不必须
                        base_prefab = base,

                        *name = string or skinname   --皮肤的名称
                        des = string or "",         --皮肤界面的描述
                        quotes = string or nil      --选人界面的描述
                        rarity = string or "Loyal", --珍惜度 官方不存在的珍惜度则直接覆盖字符串
                        rarityorder = int or -1 --  --珍惜度的排序 用于按优先级排序 基本没啥用
                        raritycorlor = {R,G,B,A} or { 0.635, 0.769, 0.435, 1 }

                        checkfn = function or nil,  检查是否拥有的 主要是客机自己执行 为空则默认拥有
                        checkclientfn = function or nil, 检查客户端是否拥有的 主要是主机执行
                        init_fn = function or nil,
                        clear_fn = function or nil,
                        share_bigportrait_name = string or nil,  --人物皮肤的背景图 大图
                        FrameSymbol = string or nil ,            --人物base皮肤的背景
                        *skins = {
                            normal_skin  = string or name,
                            ghost_skin   = string or name_ghost,
                        } or nil


                        --所有参数会顺传给返回的prefab
                            skintags = {} or nil, 皮肤的tag 用于过滤
                            assets = {} or nil,   皮肤用到的资源
                        --其他参数暂时用不到，需要的自己带进来吧，会自动传递官方的
                      }]]

    local FrameSymbol = {}
    local skincharacters = {}
    -- 人物过滤
    local SKIN_AFFINITY_INFO = require("skin_affinity_info")
    function MakeCharacterSkin(base, skinname, data)
        -- 基于哪个人物的  皮肤名称 额外数据
        data.type = nil

        -- 标记一下是拥有皮肤的人物
        if not skincharacters[base] then skincharacters[base] = true end
        characterskins[skinname] = data
        data.base_prefab = base
        data.rarity = data.rarity or "Loyal" -- 默认珍惜度
        data.build_name_override = data.build_name_override or skinname
        -- 不存在的珍惜度 自动注册字符串
        if not STRINGS.UI.RARITY[data.rarity] then
            STRINGS.UI.RARITY[data.rarity] = data.rarity
            SKIN_RARITY_COLORS[data.rarity] =
                data.raritycorlor or { 0.635, 0.769, 0.435, 1 }
            RARITY_ORDER[data.rarity] = data.rarityorder or -1
            if data.FrameSymbol then
                FrameSymbol[data.rarity] = data.FrameSymbol
            end
        end
        -- 注册到字符串
        STRINGS.SKIN_NAMES[skinname] = data.name or skinname
        STRINGS.SKIN_DESCRIPTIONS[skinname] = data.des or ""
        STRINGS.SKIN_QUOTES[skinname] = data.quotes or ""
        -- 注册到皮肤列表
        if not PREFAB_SKINS[base] then PREFAB_SKINS[base] = {} end
        table.insert(PREFAB_SKINS[base], skinname)
        if not SKIN_AFFINITY_INFO[base] then SKIN_AFFINITY_INFO[base] = {} end
        table.insert(SKIN_AFFINITY_INFO[base], skinname)

        -- 创建皮肤预制物
        local prefab_skin = CreatePrefabSkin(skinname, data)
        if data.clear_fn then prefab_skin.clear_fn = data.clear_fn end
        prefab_skin.type = "base"
        RegisterPrefabs(prefab_skin) -- 注册并加载皮肤的prefab
        TheSim:LoadPrefabs({ skinname })
        return prefab_skin
    end

    -- 物品皮肤
    local itemskins = {}
    --[[格式 skinname = {
        打*的为必填项 反之不必须
                    base = "",
                        *name = string or skinname   --皮肤的名称
                        des = string or "",         --皮肤界面的描述       好像没啥用
                        rarity = string or "Loyal", --珍惜度 官方不存在的珍惜度则直接覆盖字符串
                        rarityorder = int or -1 --      珍惜度的排序 好像没啥用
                        raritycorlor = {R,G,B,A} or { 0.635, 0.769, 0.435, 1 }  --珍惜度的颜色
                        atlas = string or nil,      --贴图xml
                        image = string or nil,        --贴图tex 不带.tex
                        --解决官方默认皮肤图标不搜索mod的问题  如果是 prefab和imagename名字一致的 建议用官方的 RegisterInventoryItemAtlas
                        bank    = string or nil,        --如果需要替换bank就传 不需要就不传
                        build   = string or skinname,   --如果需要替换build就传 不需要就默认和皮肤同名
                        anim    = string or nil,        --如果需要替换anim就传 不需要就不传

                        basebank    = string or nil,        --如果替换了bank就传 不需要就不传
                        basebuild   = string or prefab,        --如果替换了build就传 不需要默认原prefab
                        baseanim    = string or nil,        --如果替换了anim就传 不需要就不传

                        checkfn = function or nil,  检查是否拥有的 主要是客机自己执行 为空则默认拥有
                        checkclientfn = function or nil, 检查客户端是否拥有的 主要是主机执行
                        initfn = function or nil,
                        clearfn = function or nil,

                        --所有参数会顺传给返回的prefab
                            skintags = {} or nil, 皮肤的tag 用于过滤
                            assets = {} or nil,   皮肤用到的资源
                        --其他参数暂时用不到，需要的自己带进来吧，会自动传递官方的

                    }

    ]]
    local itembaseimage = {}
    function MakeItemSkinDefaultImage(base, atlas, image)
        itembaseimage[base] = { atlas, (image or base) .. ".tex", "default.tex" }
    end

    function MakeItemSkin(base, skinname, data)
        data.type = nil
        itemskins[skinname] = data
        data.base_prefab = base
        data.rarity = data.rarity or "Loyal" -- 默认珍惜度
        data.build_name_override = data.build_name_override or skinname
        -- 不存在的珍惜度 自动注册字符串
        if not STRINGS.UI.RARITY[data.rarity] then
            STRINGS.UI.RARITY[data.rarity] = data.rarity
            SKIN_RARITY_COLORS[data.rarity] =
                data.raritycorlor or { 0.635, 0.769, 0.435, 1 }
            RARITY_ORDER[data.rarity] = data.rarityorder or -1
            if data.FrameSymbol then
                FrameSymbol[data.rarity] = data.FrameSymbol
            end
        end
        -- 注册到字符串
        STRINGS.SKIN_NAMES[skinname] = data.name or skinname
        STRINGS.SKIN_DESCRIPTIONS[skinname] = data.des or ""
        if data.atlas and data.image then
            RegisterInventoryItemAtlas(data.atlas, data.image .. ".tex")
        end
        -- 注册到皮肤列表
        if not PREFAB_SKINS[base] then PREFAB_SKINS[base] = {} end
        table.insert(PREFAB_SKINS[base], skinname)
        if not PREFAB_SKINS_IDS[base] then PREFAB_SKINS_IDS[base] = {} end
        local index = 1
        for k, v in pairs(PREFAB_SKINS_IDS[base]) do index = index + 1 end
        PREFAB_SKINS_IDS[base][skinname] = index
        -- 创建皮肤预制物
        data.skininit_fn = data.init_fn or nil
        data.skinclear_fn = data.clear_fn or nil
        data.init_fn = function(i) basic_skininit_fn(i, skinname) end
        data.clear_fn = function(i) basic_skinclear_fn(i, skinname) end
        if data.skinpostfn then
            data.skinpostfn(data) -- 给一个玩家改init_fn的接口
        end
        local prefab_skin = CreatePrefabSkin(skinname, data)
        if data.clear_fn then prefab_skin.clear_fn = data.clear_fn end

        prefab_skin.type = "item"
        RegisterPrefabs(prefab_skin) -- 注册并加载皮肤的prefab
        TheSim:LoadPrefabs({ skinname })
        return prefab_skin
    end

    local namemaps = {}
    -- 允许 skinname 皮肤 共用base的权限
    function MakeSkinNameMap(base, skinname) namemaps[skinname] = base end

    function GetSkinMap(skinname) return namemaps[skinname] or skinname end

    function GetSkinMapByBase(base)
        local r = { [base] = 1 }
        for k, v in pairs(namemaps) do
            if v == base then r[k] = 1 end
        end
        return r
    end

    -- 下面的可以不看

    -- 皮肤权限hook

    local timelastest = 0

    local mt = getmetatable(TheInventory)
    local oldTheInventoryCheckOwnership = TheInventory.CheckOwnership
    mt.__index.CheckOwnership = function(i, name, ...)
        -- print(i,name,...)
        name = namemaps[name] or name
        if type(name) == "string" and (characterskins[name] or itemskins[name]) then
            if characterskins[name] and characterskins[name].checkfn then
                return characterskins[name].checkfn(i, name, ...)
            elseif itemskins[name] and itemskins[name].checkfn then
                return itemskins[name].checkfn(i, name, ...)
            else
                return true
            end
        else
            return oldTheInventoryCheckOwnership(i, name, ...)
        end
    end
    local oldTheInventoryCheckOwnershipGetLatest =
        TheInventory.CheckOwnershipGetLatest
    mt.__index.CheckOwnershipGetLatest = function(i, name, ...)
        -- print(i,name,...)
        name = namemaps[name] or name
        if type(name) == "string" and (characterskins[name] or itemskins[name]) then
            if characterskins[name] and characterskins[name].checkfn then
                return characterskins[name].checkfn(i, name, ...), timelastest
            elseif itemskins[name] and itemskins[name].checkfn then
                return itemskins[name].checkfn(i, name, ...), timelastest
            else
                return true, timelastest
            end
        else
            return oldTheInventoryCheckOwnershipGetLatest(i, name, ...)
        end
    end

    local oldTheInventoryCheckClientOwnership = TheInventory.CheckClientOwnership
    mt.__index.CheckClientOwnership = function(i, userid, name, ...)
        name = namemaps[name] or name
        if type(name) == "string" and (characterskins[name] or itemskins[name]) then
            if characterskins[name] and characterskins[name].checkclientfn then
                return characterskins[name].checkclientfn(i, userid, name, ...)
            elseif itemskins[name] and itemskins[name].checkclientfn then
                return itemskins[name].checkclientfn(i, userid, name, ...)
            else
                return true
            end
        else
            return oldTheInventoryCheckClientOwnership(i, userid, name, ...)
        end
    end

    local oldExceptionArrays = GLOBAL.ExceptionArrays
    GLOBAL.ExceptionArrays = function(ta, tb, ...)
        local need
        for i = 1, 100, 1 do
            local data = debug.getinfo(i, "S")
            if data then
                if data.source and data.source:match("^scripts/networking.lua") then
                    need = true
                end
            else
                break
            end
        end
        if need then
            local newt = oldExceptionArrays(ta, tb, ...)
            for k, v in pairs(skincharacters) do
                table.insert(newt, k) -- 偷渡
            end
            return newt
        else
            return oldExceptionArrays(ta, tb, ...)
        end
    end
    local oldIsDefaultCharacterSkin = IsDefaultCharacterSkin
    GLOBAL.IsDefaultCharacterSkin = function(item, ...)
        item = item and namemaps[item] or item
        if item and characterskins[item] then
            if characterskins[item].checkfn then
                return characterskins[item].checkfn(nil, item)
            else
                return true
            end
        else
            return oldIsDefaultCharacterSkin(item, ...)
        end
    end
    local oldGetPortraitNameForItem = GetPortraitNameForItem
    GLOBAL.GetPortraitNameForItem = function(item)
        item = item and namemaps[item] or item
        if item and characterskins[item] and
            characterskins[item].share_bigportrait_name then
            return characterskins[item].share_bigportrait_name
        end
        return oldGetPortraitNameForItem(item)
    end
    local oldGetFrameSymbolForRarity = GetFrameSymbolForRarity
    GLOBAL.GetFrameSymbolForRarity = function(item)
        item = item and namemaps[item] or item
        return FrameSymbol[item] or oldGetFrameSymbolForRarity(item)
    end
    -- 骗过皮肤面板，让他以为我们是官方人物
    local function rainlightbaseenable(self)
        if self.name == "LoadoutSelect" then -- 加载LoadoutSelect之前
            for k, v in pairs(skincharacters) do
                if not table.contains(DST_CHARACTERLIST, k) then
                    table.insert(DST_CHARACTERLIST, k)
                end
            end
        elseif self.name == "LoadoutRoot" then -- 已经判断完have_base_option了  可以删了 哈哈
            for k, v in pairs(skincharacters) do
                if table.contains(DST_CHARACTERLIST, k) then
                    RemoveByValue(DST_CHARACTERLIST, k)
                end
            end
        end
    end
    AddClassPostConstruct("widgets/widget", rainlightbaseenable)
    AddSimPostInit(function()
        if not TheNet:IsOnlineMode() then
            local net = getmetatable(GLOBAL.TheNet)
            net.__index.IsOnlineMode = function(n, ...) return true end
        end
    end)
    -- 人物皮肤的init_fn 和 clear_fn
    AddComponentPostInit("skinner", function(self)
        local oldfn = self.SetSkinName
        if oldfn then
            function self.SetSkinName(s, skinname, ...)
                local old = s.skin_name
                local new = skinname
                if characterskins[old] and characterskins[old].clear_fn then
                    characterskins[old].clear_fn(s.inst, old)
                end
                if characterskins[new] and characterskins[new].init_fn then
                    characterskins[new].init_fn(s.inst, new)
                end
                oldfn(s, skinname, ...)
            end
        end
    end)

    AddClassPostConstruct("widgets/recipepopup", function(self)
        local oldfn = self.GetSkinOptions
        function self.GetSkinOptions(s, ...)
            local ret = oldfn(s, ...)
            if ret then
                if ret[1] and ret[1].image then
                    if s.recipe and s.recipe.product and
                        itembaseimage[s.recipe.product] then -- 存在则覆盖
                        ret[1].image = itembaseimage[s.recipe.product]
                    end
                end
                for k, v in pairs(s.skins_list) do
                    if ret[k + 1] and ret[k + 1].image and v and v.item and
                        itemskins[v.item] and
                        (itemskins[v.item].atlas or itemskins[v.item].image) then
                        local image = itemskins[v.item].image or v.item .. ".tex"
                        if image:sub(-4) ~= ".tex" then
                            image = image .. ".tex"
                        end
                        local atlas = itemskins[v.item].atlas or
                            GetInventoryItemAtlas(image)
                        ret[k + 1].image = { atlas, image, "default.tex" }
                    end
                end
            end
            return ret
        end
    end)

    local skinselector = require("widgets/redux/craftingmenu_skinselector")
    function hookskinselector(self)
        local oldfn = self.GetSkinOptions
        function self.GetSkinOptions(s, ...)
            local ret = oldfn(s, ...)
            if ret then
                if ret[1] and ret[1].image then
                    if s.recipe and s.recipe.product and
                        itembaseimage[s.recipe.product] then -- 存在则覆盖
                        ret[1].image = itembaseimage[s.recipe.product]
                    end
                end
                for k, v in pairs(s.skins_list) do
                    if ret[k + 1] and ret[k + 1].image and v and v.item and
                        itemskins[v.item] and
                        (itemskins[v.item].atlas or itemskins[v.item].image) then
                        local image = itemskins[v.item].image or v.item .. ".tex"
                        if image:sub(-4) ~= ".tex" then
                            image = image .. ".tex"
                        end
                        local atlas = itemskins[v.item].atlas or
                            GetInventoryItemAtlas(image)
                        ret[k + 1].image = { atlas, image, "default.tex" }
                    end
                end
            end
            return ret
        end
    end

    hookskinselector(skinselector)
    local oldGetSkinInvIconName = GetSkinInvIconName
    GLOBAL.GetSkinInvIconName = function(item, ...)
        if itemskins[item] and itemskins[item].image then
            local image = itemskins[item].image
            if image:sub(-4) == ".tex" then image = image:sub(1, -5) end
            return image
        end
        return oldGetSkinInvIconName(item, ...)
    end

    -- 这是全局函数 所以可以放后面 在执行前定义好就行
    function basic_skininit_fn(inst, skinname)
        if inst.components.placer == nil and not TheWorld.ismastersim then return end
        local data = itemskins[skinname]
        if not data then return end
        if data.bank then inst.AnimState:SetBank(data.bank) end
        inst.AnimState:SetBuild(data.build or skinname)
        if data.anim then -- 改了下【雨荧
            if data.animcircle then
                inst.AnimState:PlayAnimation(data.anim, true)
            else
                inst.AnimState:PlayAnimation(data.anim)
            end
        end
        if inst.components.inventoryitem ~= nil then
            inst.components.inventoryitem.atlasname =
                data.atlas or ("images/inventoryimages/" .. skinname .. ".xml")
            inst.components.inventoryitem:ChangeImageName(data.image or skinname)
        end
        if data.skininit_fn then data.skininit_fn(inst, skinname) end
    end

    function basic_skinclear_fn(inst, skinname) -- 默认认为 build 和prefab同名 不对的话自己改
        local prefab = inst.prefab or ""
        local data = itemskins[skinname]
        if not data then return end
        if data.basebank then inst.AnimState:SetBank(data.basebank) end
        if data.baseanim then -- 改了下【雨荧
            if data.baseanimcircle then
                inst.AnimState:PlayAnimation(data.baseanim, true)
            else
                inst.AnimState:PlayAnimation(data.baseanim)
            end
        end
        inst.AnimState:SetBuild(data.basebuild or prefab)
        if inst.components.inventoryitem ~= nil then
            inst.components.inventoryitem.atlasname =
                GetInventoryItemAtlas(prefab .. ".tex")
            inst.components.inventoryitem:ChangeImageName(prefab)
        end
        if itemskins[skinname].skinclear_fn then
            itemskins[skinname].skinclear_fn(inst, skinname)
        end
    end

    local oldSpawnPrefab = SpawnPrefab
    GLOBAL.SpawnPrefab = function(prefab, skin, skinid, userid, ...)
        if itemskins[skin] then skinid = 0 end
        return oldSpawnPrefab(prefab, skin, skinid, userid, ...)
    end
    local oldReskinEntity = Sim.ReskinEntity
    Sim.ReskinEntity = function(sim, guid, oldskin, newskin, skinid, userid, ...)
        local inst = Ents[guid]
        if oldskin and itemskins[oldskin] then
            itemskins[oldskin].clear_fn(inst) -- 清除旧皮肤的
        end
        local r = oldReskinEntity(sim, guid, oldskin, newskin, skinid, userid, ...)
        if newskin and itemskins[newskin] then
            itemskins[newskin].init_fn(inst)
            inst.skinname = newskin
            inst.skin_id = 0
        end
        return r
    end

    function GetSkin(name) return characterskins[name] or itemskins[name] or nil end

    if recipe_help then
        AddSimPostInit(function()
            for k, v in pairs(AllRecipes) do
                if v.product ~= v.name and PREFAB_SKINS[v.product] then
                    PREFAB_SKINS[v.name] = PREFAB_SKINS[v.product]
                    PREFAB_SKINS_IDS[v.name] = PREFAB_SKINS_IDS[v.product]
                end
            end
        end)
    end

    if thank_help then
        local ThankYouPopup = require "screens/thankyoupopup"
        local tohook = {
            OpenGift = 1,
            ChangeGift = 1
        }
        for k, v in pairs(tohook) do
            tohook[k] = ThankYouPopup[k]
            ThankYouPopup[k] = function(self, ...)
                local r = tohook[k](self, ...)

                local item = self.current_item and self.items and self.items[self.current_item] and
                    self.items[self.current_item].item
                if item then
                    local skin = GetSkin(item)
                    if skin and skin.swap_icon then
                        self.spawn_portal:GetAnimState():OverrideSkinSymbol("SWAP_ICON", skin.swap_icon.build,
                            skin.swap_icon.image)
                    elseif skin and skin.image and skin.atlas then
                        self.spawn_portal:GetAnimState():OverrideSkinSymbol("SWAP_ICON", softresolvefilepath(skin.atlas),
                            skin.image .. ".tex")
                    end
                end

                return r
            end
        end
    end

    local oldCreatePrefabSkin = GLOBAL.CreatePrefabSkin
    local fninfo = debug.getinfo(oldCreatePrefabSkin)
    if fninfo and fninfo.source and
        not fninfo.source:match("scripts/prefabskin%.lua") then -- 不是官方的就用自己的
        -- print("UseMySelfCreatePrefabSkin")
        function CreatePrefabSkin(name, info)
            local prefab_skin = Prefab(name, nil, info.assets, info.prefabs)
            prefab_skin.is_skin = true
            -- Hack to deal with mods with bad data. Type is now required, and who knows how many character mods are missing this field.
            if info.type == nil then info.type = "base" end
            prefab_skin.base_prefab = info.base_prefab
            prefab_skin.type = info.type
            prefab_skin.skin_tags = info.skin_tags
            prefab_skin.init_fn = info.init_fn
            prefab_skin.build_name_override = info.build_name_override
            prefab_skin.bigportrait = info.bigportrait
            prefab_skin.rarity = info.rarity
            prefab_skin.rarity_modifier = info.rarity_modifier
            prefab_skin.skins = info.skins
            prefab_skin.skin_sound = info.skin_sound
            prefab_skin.is_restricted = info.is_restricted
            prefab_skin.granted_items = info.granted_items
            prefab_skin.marketable = info.marketable
            prefab_skin.release_group = info.release_group
            prefab_skin.linked_beard = info.linked_beard
            prefab_skin.share_bigportrait_name = info.share_bigportrait_name
            if info.torso_tuck_builds ~= nil then
                for _, base_skin in pairs(info.torso_tuck_builds) do
                    GLOBAL.BASE_TORSO_TUCK[base_skin] = "full"
                end
            end
            if info.torso_untuck_builds ~= nil then
                for _, base_skin in pairs(info.torso_untuck_builds) do
                    GLOBAL.BASE_TORSO_TUCK[base_skin] = "untucked"
                end
            end
            if info.torso_untuck_wide_builds ~= nil then
                for _, base_skin in pairs(info.torso_untuck_wide_builds) do
                    GLOBAL.BASE_TORSO_TUCK[base_skin] = "untucked_wide"
                end
            end
            if info.has_alternate_for_body ~= nil then
                for _, base_skin in pairs(info.has_alternate_for_body) do
                    GLOBAL.BASE_ALTERNATE_FOR_BODY[base_skin] = true
                end
            end
            if info.has_alternate_for_skirt ~= nil then
                for _, base_skin in pairs(info.has_alternate_for_skirt) do
                    GLOBAL.BASE_ALTERNATE_FOR_SKIRT[base_skin] = true
                end
            end
            if info.one_piece_skirt_builds ~= nil then
                for _, base_skin in pairs(info.one_piece_skirt_builds) do
                    GLOBAL.ONE_PIECE_SKIRT[base_skin] = true
                end
            end
            if info.legs_cuff_size ~= nil then
                for base_skin, size in pairs(info.legs_cuff_size) do
                    GLOBAL.BASE_LEGS_SIZE[base_skin] = size
                end
            end
            if info.feet_cuff_size ~= nil then
                for base_skin, size in pairs(info.feet_cuff_size) do
                    GLOBAL.BASE_FEET_SIZE[base_skin] = size
                end
            end
            if info.skin_sound ~= nil then
                GLOBAL.SKIN_SOUND_FX[name] = info.skin_sound
            end
            if info.fx_prefab ~= nil then
                GLOBAL.SKIN_FX_PREFAB[name] = info.fx_prefab
            end
            if info.type ~= "base" then
                prefab_skin.clear_fn = _G[prefab_skin.base_prefab .. "_clear_fn"]
            end
            return prefab_skin
        end
    else
        CreatePrefabSkin = oldCreatePrefabSkin
    end
end
do
    -- 皮肤API
    GLOBAL[string.upper(modname) .. "_API"] = env

    local avatar_name = playerinfo.prefabname

    table.insert(PrefabFiles, 'avatar_' .. avatar_name)

    local assets_avatar = {
        Asset('ATLAS', 'images/saveslot_portraits/' .. avatar_name .. '.xml'),

        Asset('ATLAS', 'images/selectscreen_portraits/' .. avatar_name .. '.xml'),

        Asset('ATLAS', 'images/selectscreen_portraits/' .. avatar_name .. '_silho.xml'),

        Asset('ATLAS', 'bigportraits/' .. avatar_name .. '.xml'),

        Asset('ATLAS', 'images/map_icons/' .. avatar_name .. '.xml'),

        Asset('ATLAS', 'images/avatars/avatar_' .. avatar_name .. '.xml'),

        Asset('ATLAS', 'images/avatars/avatar_ghost_' .. avatar_name .. '.xml'),

        Asset('ATLAS', 'images/avatars/self_inspect_' .. avatar_name .. '.xml'),

        Asset('ATLAS', 'images/names_' .. avatar_name .. '.xml'),

        Asset('ATLAS', 'bigportraits/' .. avatar_name .. '_none.xml'),
    }

    for _, v in pairs(assets_avatar) do
        table.insert(Assets, v)
    end

    --[[---注意事项
1. 目前官方自从熔炉之后人物的界面显示用的都是那个椭圆的图
2. 官方人物目前的图片跟名字是分开的
3. 用打包工具生成好tex后
	bigportraits/xxx_none.xml 中 Element name 加上后缀 _oval
    images/names_xxx.xml 中 Element name 去掉前缀 names_
]]


    modimport('scripts/api_skins/' .. avatar_name .. '_skins') -- 皮肤api

    -- 初始物品
    TUNING[string.upper(playerinfo.prefabname) .. "_CUSTOM_START_INV"] = playerinfo.prefabinfo.startinv or {
        -- ['goldnugget'] = {
        -- 	num = 4, -- 数量
        -- 	moditem = false, -- 是否为mod物品
        -- 	-- img = {atlas = 'images/inventoryimages/goldnugget.xml', image = 'goldnugget.tex'},
        -- },
        -- ['flint'] = {
        -- 	num = 3,
        -- 	moditem = false,
        -- },
    }

    TUNING.GAMEMODE_STARTING_ITEMS.DEFAULT[string.upper(avatar_name)] = {}
    for k, v in pairs(TUNING[string.upper(playerinfo.prefabname) .. "_CUSTOM_START_INV"]) do
        table.insert(TUNING.GAMEMODE_STARTING_ITEMS.DEFAULT[string.upper(avatar_name)], k)
        if v.moditem then
            TUNING.STARTING_ITEM_IMAGE_OVERRIDE[v] = {
                atlas = v.img and v.img.atlas or "images/inventoryimages/" .. k .. ".xml",
                image = v.img and v.img.image or k .. ".tex",
            }
        end
    end

    -- 角色注册
    AddMinimapAtlas("images/map_icons/" .. avatar_name .. ".xml")
    AddModCharacter(avatar_name, "FEMALE")

    -- 三维
    TUNING[string.upper(avatar_name) .. '_HEALTH'] = playerinfo.prefabinfo.maxhealth
    TUNING[string.upper(avatar_name) .. '_HUNGER'] = playerinfo.prefabinfo.maxhunger
    TUNING[string.upper(avatar_name) .. '_SANITY'] = playerinfo.prefabinfo.maxsanity

    local avatar_info = playerinfo.avatar_info

    STRINGS.CHARACTER_TITLES[avatar_name] = avatar_info[language].titles
    STRINGS.CHARACTER_NAMES[avatar_name] = avatar_info[language].names
    STRINGS.CHARACTER_DESCRIPTIONS[avatar_name] = avatar_info[language]
        .descriptions
    STRINGS.CHARACTER_QUOTES[avatar_name] = avatar_info[language].quotes
    STRINGS.CHARACTER_SURVIVABILITY[avatar_name] = avatar_info[language]
        .survivability

    if STRINGS.CHARACTERS[string.upper(avatar_name)] == nil then
        STRINGS.CHARACTERS[string.upper(avatar_name)] = {}
    end

    if STRINGS.CHARACTERS[string.upper(avatar_name)].DESCRIBE == nil then
        STRINGS.CHARACTERS[string.upper(avatar_name)].DESCRIBE = {}
    end

    STRINGS.NAMES[string.upper(avatar_name)] = avatar_info[language].myname
    STRINGS.CHARACTERS.GENERIC.DESCRIBE[string.upper(avatar_name)] = avatar_info
        [language]
        .others_desc_me
    STRINGS.CHARACTERS[string.upper(avatar_name)].DESCRIBE[string.upper(avatar_name)] = avatar_info
        [language]
        .me_desc_another_me
end
do
    local function playerprefabfn()
        local MakePlayerCharacter = require 'prefabs/player_common'
        local avatar_name = playerinfo.prefabname
        local assets = {
            Asset('SCRIPT', 'scripts/prefabs/player_common.lua'),
            Asset('ANIM', 'anim/' .. avatar_name .. '.zip'),
            Asset('ANIM', 'anim/ghost_' .. avatar_name .. '_build.zip'),
        }
        if playerinfo.extraplayerassets then
            for k, v in pairs(playerinfo.extraplayerassets) do
                table.insert(assets, v)
            end
        end
        local prefabs = {}
        local start_inv = {}
        start_inv['default'] = {}
        for k, v in pairs(TUNING[string.upper(playerinfo.prefabname) .. "_CUSTOM_START_INV"]) do
            for i = 1, v.num do
                table.insert(start_inv['default'], k)
            end
        end
        prefabs = FlattenTree({ prefabs, start_inv }, true)
        local function onload(inst, data)
        end
        ---------------------------------------------------------------------------
        ---------------------------------------------------------------------------
        -- 主/客机
        local common_postinit = function(inst)
            inst:AddTag(avatar_name)

            if playerinfo.common_postinit then
                playerinfo.common_postinit(inst)
            end

            inst.MiniMapEntity:SetIcon(avatar_name .. '.tex')
        end
        -- 主机
        local master_postinit = function(inst)
            inst.starting_inventory = start_inv[TheNet:GetServerGameMode()] or start_inv.default
            inst.soundsname = playerinfo.prefabinfo.soundsname or 'wendy'

            inst.components.health:SetMaxHealth(TUNING[string.upper(avatar_name) .. '_HEALTH'])
            inst.components.hunger:SetMax(TUNING[string.upper(avatar_name) .. '_HUNGER'])
            inst.components.sanity:SetMax(TUNING[string.upper(avatar_name) .. '_SANITY'])
            if playerinfo.ezsetup.ignorecurse then
                if inst.components.cursable then --免疫猴子诅咒
                    inst.components.cursable.IsCursable = function(...)
                        return false
                    end
                    inst.components.cursable.ApplyCurse = function(...)

                    end
                end
            end
            if playerinfo.master_postinit then
                playerinfo.master_postinit(inst)
            end
            inst.OnLoad = onload
            inst.OnNewSpawn = onload
        end
        -- 人物皮肤
        local function MakeSkin(name, data, notemp, free)
            local d = {}
            d.rarity = '典藏'
            d.rarityorder = 2
            d.raritycorlor = { 0 / 255, 255 / 255, 249 / 255, 1 }
            d.release_group = -1001
            d.skin_tags = { 'BASE', avatar_name, 'CHARACTER' }
            d.skins = {
                normal_skin = name,
                ghost_skin = 'ghost_' .. avatar_name .. '_build'
            }
            if not free then
                d.checkfn = _G[string.upper(modname) .. "_API"].SkinCheckFn
                d.checkclientfn = _G[string.upper(modname) .. "_API"].SkinCheckFn
            end
            d.share_bigportrait_name = avatar_name
            d.FrameSymbol = 'Reward'
            for k, v in pairs(data) do
                d[k] = v
            end
            _G[string.upper(modname) .. "_API"].MakeCharacterSkin(avatar_name, name, d)
            if not notemp then
                local d2 = shallowcopy(d)
                d2.rarity = '限时体验'
                d2.rarityorder = 80
                d2.raritycorlor = { 0.957, 0.769, 0.188, 1 }
                d2.FrameSymbol = 'heirloom'
                d2.name = data.name .. '(限时)'
                _G[string.upper(modname) .. "_API"].MakeCharacterSkin(avatar_name, name .. '_tmp', d2)
            end
        end
        local function MakeFreeSkin(name, data)
            MakeSkin(name, data, true, true)
        end
        if playerinfo.skins then
            if playerinfo.skins.default then
                local d = playerinfo.skins.default
                MakeFreeSkin(avatar_name .. '_none', {
                    name = d.name,                 -- 皮肤的名称
                    des = d.des,                   -- 皮肤界面的描述
                    quotes = d.quotes,             -- 选人界面的描述
                    rarity = d.rarity,             -- 珍惜度 官方不存在的珍惜度则直接覆盖字符串
                    rarityorder = d.rarityorder,   -- 珍惜度的排序 用于按优先级排序 基本没啥用
                    raritycorlor = d.raritycorlor, -- {R,G,B,A}
                    skins = { normal_skin = avatar_name, ghost_skin = 'ghost_' .. avatar_name .. '_build' },
                    build_name_override = avatar_name,
                    share_bigportrait_name = avatar_name .. '_none',
                })
            end
            for k, v in pairs(playerinfo.skins.extraskin) do
                MakeFreeSkin(k, v)
            end
        end



        return MakePlayerCharacter(avatar_name, prefabs, assets, common_postinit, master_postinit, prefabs)
    end
    MOD_util:RegisterModPrefab('avatar_' .. playerinfo.prefabname, playerprefabfn)
end
